﻿using System;
using System.IO;

namespace TrekBattle
{
    class Ship
    {
        private const int MAXIMUM_PERCENTAGE = 100;
        enum Damage {   UNDAMAGED = 100,
                        LIGHTLY_DAMAGED = 90,
                        MODERATELY_DAMAGED = 70,
                        HEAVILY_DAMAGED = 40,
                        VERY_HEAVILY_DAMAGED = 0    }

        private readonly string ShipFilename;

        // Ship attributes
        private readonly string Name;

        private readonly int ShieldStrength;
        private int CurrentShieldStrength;
        private readonly int RegenerationRate;

        private readonly int HullStrength;
        private int CurrentHullStrength;

        private readonly int WeaponBaseDamage;
        private readonly int WeaponRandomDamage;

        // Ship state flags
        private bool Destroyed = false;
        private bool BeenHit = false;

        public Ship(StreamReader fin, String shipFilename)
        {
            ShipFilename = shipFilename;
            Name = fin.ReadLine();

            ShieldStrength = ReadNextInt(fin, "shield strength");
            CurrentShieldStrength = ShieldStrength;
            RegenerationRate = ReadNextInt(fin, "regen rate");
            HullStrength = ReadNextInt(fin, "hull strength");
            CurrentHullStrength = HullStrength;
            WeaponBaseDamage = ReadNextInt(fin, "weapon base");
            WeaponRandomDamage = ReadNextInt(fin, "weapon random");
        }

        private int ReadNextInt(StreamReader fin, String readErrorType)
        {
            int returnInt;
            bool parseSuccess = Int32.TryParse(fin.ReadLine(), out returnInt);

            if ((parseSuccess == false) || (returnInt <= 0))
                EndProgram("Invalid " + readErrorType + " in ship class " + Name + " in the file " + ShipFilename);

            return returnInt;
        }

        public string GetName()
        {
            return Name;
        }

        public int GetWeaponBaseDamage()
        {
            return WeaponBaseDamage;
        }

        public int GetWeaponRandomDamage()
        {
            return WeaponRandomDamage;
        }

        public void Hit(int damage)
        {
            BeenHit = true;
            int surplusDamage = HitShield(damage);

            if (surplusDamage > 0)
                HitHull(surplusDamage);
        }

        private int HitShield(int damage)
        {
            // Damage the shields first
            CurrentShieldStrength -= damage;

            // Check for excess shield damage; if any return that surplus amount
            int SurplusDamage = 0;
            if (CurrentShieldStrength < 0)
            {
                SurplusDamage = Math.Abs(CurrentShieldStrength); // Any amount of shields < 0 should be applied to the hull instead
                CurrentShieldStrength = 0;
            }
            return SurplusDamage;
        }

        private void HitHull(int damage)
        {
            CurrentHullStrength -= damage;

            if (CurrentHullStrength <= 0)
                Destroyed = true;
        }

        public void RechargeShield()
        {
            if (BeenHit == false)
            {
                CurrentShieldStrength += RegenerationRate;
                if (CurrentShieldStrength > ShieldStrength)
                    CurrentShieldStrength = ShieldStrength;
            }
            else
                BeenHit = false; // Reset the flag for the next round of attacks
        }

        public string DamageLevel()
        {
            int percentageUndamaged = (int)CurrentHullStrength * MAXIMUM_PERCENTAGE / HullStrength;

            if (percentageUndamaged >= (int) Damage.UNDAMAGED)
                return "undamaged";
            else if (percentageUndamaged >= (int) Damage.LIGHTLY_DAMAGED)
                return "lightly damaged";
            else if (percentageUndamaged >= (int) Damage.MODERATELY_DAMAGED)
                return "moderately damaged";
            else if (percentageUndamaged >= (int) Damage.HEAVILY_DAMAGED)
                return "heavily damaged";
            else
                return "very heavily damaged";
        }

        public bool hasBeenHit()
        {
            return BeenHit;
        }

        public bool isDestroyed()
        {
            return Destroyed;
        }

        private static void EndProgram(string errorText)
        {
            Console.WriteLine("Program failed with the following error");
            Console.WriteLine(errorText);
            Environment.Exit(0);
        }
    }
}